/**
 * 时间日期工具函数 - JavaScript版本
 * 提供时间格式化、解析、计算、转换等功能
 * 支持直接复制粘贴使用，无需任何依赖
 * 每个函数都是独立的，可以单独复制使用
 */

// 常量定义
const TIME_UNITS = {
  MILLISECOND: 'millisecond',
  SECOND: 'second',
  MINUTE: 'minute',
  HOUR: 'hour',
  DAY: 'day',
  WEEK: 'week',
  MONTH: 'month',
  YEAR: 'year'
};

const DATE_FORMATS = {
  YYYY_MM_DD: 'YYYY-MM-DD',
  YYYY_MM_DD_HH_MM_SS: 'YYYY-MM-DD HH:mm:ss',
  MM_DD_YYYY: 'MM/DD/YYYY',
  DD_MM_YYYY: 'DD/MM/YYYY',
  YYYY_MM_DD_HH_MM: 'YYYY-MM-DD HH:mm',
  HH_MM_SS: 'HH:mm:ss',
  HH_MM: 'HH:mm'
};

/**
 * 格式化日期
 * @param {Date|string|number} date - 日期
 * @param {string} format - 格式字符串
 * @returns {string} 格式化后的日期字符串
 */
function formatDate(date, format = DATE_FORMATS.YYYY_MM_DD) {
  if (!date) return '';
  
  const d = new Date(date);
  if (isNaN(d.getTime())) return '';
  
  const year = d.getFullYear();
  const month = String(d.getMonth() + 1).padStart(2, '0');
  const day = String(d.getDate()).padStart(2, '0');
  const hours = String(d.getHours()).padStart(2, '0');
  const minutes = String(d.getMinutes()).padStart(2, '0');
  const seconds = String(d.getSeconds()).padStart(2, '0');
  
  return format
    .replace('YYYY', year)
    .replace('MM', month)
    .replace('DD', day)
    .replace('HH', hours)
    .replace('mm', minutes)
    .replace('ss', seconds);
}

/**
 * 解析日期字符串
 * @param {string} dateString - 日期字符串
 * @returns {Date|null} 解析后的日期对象
 */
function parseDate(dateString) {
  if (!dateString || typeof dateString !== 'string') return null;
  
  const date = new Date(dateString);
  return isNaN(date.getTime()) ? null : date;
}

/**
 * 获取相对时间
 * @param {Date|string|number} date - 日期
 * @param {Date|string|number} baseDate - 基准日期，默认为当前时间
 * @returns {string} 相对时间字符串
 */
function getTimeAgo(date, baseDate = new Date()) {
  if (!date) return '';
  
  const targetDate = new Date(date);
  const base = new Date(baseDate);
  
  if (isNaN(targetDate.getTime()) || isNaN(base.getTime())) return '';
  
  const diffMs = base.getTime() - targetDate.getTime();
  const diffSeconds = Math.floor(diffMs / 1000);
  const diffMinutes = Math.floor(diffSeconds / 60);
  const diffHours = Math.floor(diffMinutes / 60);
  const diffDays = Math.floor(diffHours / 24);
  const diffWeeks = Math.floor(diffDays / 7);
  const diffMonths = Math.floor(diffDays / 30);
  const diffYears = Math.floor(diffDays / 365);
  
  if (diffSeconds < 60) {
    return '刚刚';
  } else if (diffMinutes < 60) {
    return `${diffMinutes}分钟前`;
  } else if (diffHours < 24) {
    return `${diffHours}小时前`;
  } else if (diffDays < 7) {
    return `${diffDays}天前`;
  } else if (diffWeeks < 4) {
    return `${diffWeeks}周前`;
  } else if (diffMonths < 12) {
    return `${diffMonths}个月前`;
  } else {
    return `${diffYears}年前`;
  }
}

/**
 * 检查日期是否有效
 * @param {Date|string|number} date - 日期
 * @returns {boolean} 是否有效
 */
function isValidDate(date) {
  if (!date) return false;
  
  const d = new Date(date);
  return !isNaN(d.getTime());
}

/**
 * 添加天数
 * @param {Date|string|number} date - 日期
 * @param {number} days - 天数
 * @returns {Date} 新的日期对象
 */
function addDays(date, days) {
  const d = new Date(date);
  d.setDate(d.getDate() + days);
  return d;
}

/**
 * 添加小时
 * @param {Date|string|number} date - 日期
 * @param {number} hours - 小时数
 * @returns {Date} 新的日期对象
 */
function addHours(date, hours) {
  const d = new Date(date);
  d.setHours(d.getHours() + hours);
  return d;
}

/**
 * 添加分钟
 * @param {Date|string|number} date - 日期
 * @param {number} minutes - 分钟数
 * @returns {Date} 新的日期对象
 */
function addMinutes(date, minutes) {
  const d = new Date(date);
  d.setMinutes(d.getMinutes() + minutes);
  return d;
}

/**
 * 添加月份
 * @param {Date|string|number} date - 日期
 * @param {number} months - 月数
 * @returns {Date} 新的日期对象
 */
function addMonths(date, months) {
  const d = new Date(date);
  d.setMonth(d.getMonth() + months);
  return d;
}

/**
 * 添加年份
 * @param {Date|string|number} date - 日期
 * @param {number} years - 年数
 * @returns {Date} 新的日期对象
 */
function addYears(date, years) {
  const d = new Date(date);
  d.setFullYear(d.getFullYear() + years);
  return d;
}

/**
 * 获取日期范围
 * @param {Date|string|number} startDate - 开始日期
 * @param {Date|string|number} endDate - 结束日期
 * @returns {Object} 日期范围信息
 */
function getDateRange(startDate, endDate) {
  const start = new Date(startDate);
  const end = new Date(endDate);
  
  if (isNaN(start.getTime()) || isNaN(end.getTime())) {
    return {
      isValid: false,
      days: 0,
      hours: 0,
      minutes: 0,
      seconds: 0,
      milliseconds: 0
    };
  }
  
  const diffMs = end.getTime() - start.getTime();
  const diffSeconds = Math.floor(diffMs / 1000);
  const diffMinutes = Math.floor(diffSeconds / 60);
  const diffHours = Math.floor(diffMinutes / 60);
  const diffDays = Math.floor(diffHours / 24);
  
  return {
    isValid: true,
    days: diffDays,
    hours: diffHours,
    minutes: diffMinutes,
    seconds: diffSeconds,
    milliseconds: diffMs
  };
}

/**
 * 时区转换
 * @param {Date|string|number} date - 日期
 * @param {string} fromTz - 源时区
 * @param {string} toTz - 目标时区
 * @returns {Date} 转换后的日期
 */
function timezoneConvert(date, fromTz, toTz) {
  const d = new Date(date);
  if (isNaN(d.getTime())) return d;
  
  // 简单的时区转换实现
  const offsetMap = {
    'UTC': 0,
    'GMT': 0,
    'EST': -5,
    'PST': -8,
    'CST': -6,
    'MST': -7,
    'JST': 9,
    'CET': 1,
    'EET': 2,
    'IST': 5.5,
    'AEST': 10,
    'NZST': 12
  };
  
  const fromOffset = offsetMap[fromTz] || 0;
  const toOffset = offsetMap[toTz] || 0;
  const offsetDiff = toOffset - fromOffset;
  
  return new Date(d.getTime() + offsetDiff * 60 * 60 * 1000);
}

/**
 * 获取周数
 * @param {Date|string|number} date - 日期
 * @returns {number} 周数
 */
function getWeekNumber(date) {
  const d = new Date(date);
  if (isNaN(d.getTime())) return 0;
  
  const firstDayOfYear = new Date(d.getFullYear(), 0, 1);
  const pastDaysOfYear = (d - firstDayOfYear) / 86400000;
  return Math.ceil((pastDaysOfYear + firstDayOfYear.getDay() + 1) / 7);
}

/**
 * 检查是否为闰年
 * @param {number} year - 年份
 * @returns {boolean} 是否为闰年
 */
function isLeapYear(year) {
  return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
}

/**
 * 计算年龄
 * @param {Date|string|number} birthDate - 出生日期
 * @param {Date|string|number} currentDate - 当前日期，默认为当前时间
 * @returns {number} 年龄
 */
function getAge(birthDate, currentDate = new Date()) {
  const birth = new Date(birthDate);
  const current = new Date(currentDate);
  
  if (isNaN(birth.getTime()) || isNaN(current.getTime())) return 0;
  
  let age = current.getFullYear() - birth.getFullYear();
  const monthDiff = current.getMonth() - birth.getMonth();
  
  if (monthDiff < 0 || (monthDiff === 0 && current.getDate() < birth.getDate())) {
    age--;
  }
  
  return Math.max(0, age);
}

/**
 * 获取月份天数
 * @param {number} year - 年份
 * @param {number} month - 月份（1-12）
 * @returns {number} 天数
 */
function getDaysInMonth(year, month) {
  return new Date(year, month, 0).getDate();
}

/**
 * 获取月份第一天
 * @param {Date|string|number} date - 日期
 * @returns {Date} 月份第一天
 */
function getFirstDayOfMonth(date) {
  const d = new Date(date);
  return new Date(d.getFullYear(), d.getMonth(), 1);
}

/**
 * 获取月份最后一天
 * @param {Date|string|number} date - 日期
 * @returns {Date} 月份最后一天
 */
function getLastDayOfMonth(date) {
  const d = new Date(date);
  return new Date(d.getFullYear(), d.getMonth() + 1, 0);
}

/**
 * 获取周第一天
 * @param {Date|string|number} date - 日期
 * @param {number} startDay - 周开始日（0=周日，1=周一）
 * @returns {Date} 周第一天
 */
function getFirstDayOfWeek(date, startDay = 1) {
  const d = new Date(date);
  const day = d.getDay();
  const diff = day - startDay;
  return new Date(d.getTime() - diff * 24 * 60 * 60 * 1000);
}

/**
 * 获取周最后一天
 * @param {Date|string|number} date - 日期
 * @param {number} startDay - 周开始日（0=周日，1=周一）
 * @returns {Date} 周最后一天
 */
function getLastDayOfWeek(date, startDay = 1) {
  const firstDay = getFirstDayOfWeek(date, startDay);
  return addDays(firstDay, 6);
}

/**
 * 比较日期
 * @param {Date|string|number} date1 - 日期1
 * @param {Date|string|number} date2 - 日期2
 * @returns {number} 比较结果（-1: date1 < date2, 0: 相等, 1: date1 > date2）
 */
function compareDates(date1, date2) {
  const d1 = new Date(date1);
  const d2 = new Date(date2);
  
  if (isNaN(d1.getTime()) || isNaN(d2.getTime())) return 0;
  
  if (d1.getTime() < d2.getTime()) return -1;
  if (d1.getTime() > d2.getTime()) return 1;
  return 0;
}

/**
 * 检查日期是否在范围内
 * @param {Date|string|number} date - 日期
 * @param {Date|string|number} startDate - 开始日期
 * @param {Date|string|number} endDate - 结束日期
 * @returns {boolean} 是否在范围内
 */
function isDateInRange(date, startDate, endDate) {
  const d = new Date(date);
  const start = new Date(startDate);
  const end = new Date(endDate);
  
  if (isNaN(d.getTime()) || isNaN(start.getTime()) || isNaN(end.getTime())) {
    return false;
  }
  
  return d.getTime() >= start.getTime() && d.getTime() <= end.getTime();
}

/**
 * 获取时间戳
 * @param {Date|string|number} date - 日期
 * @returns {number} 时间戳（毫秒）
 */
function getTimestamp(date) {
  const d = new Date(date);
  return isNaN(d.getTime()) ? 0 : d.getTime();
}

/**
 * 从时间戳创建日期
 * @param {number} timestamp - 时间戳
 * @returns {Date} 日期对象
 */
function fromTimestamp(timestamp) {
  return new Date(timestamp);
}

/**
 * 获取当前时间戳
 * @returns {number} 当前时间戳
 */
function getCurrentTimestamp() {
  return Date.now();
}

/**
 * 格式化时间戳
 * @param {number} timestamp - 时间戳
 * @param {string} format - 格式字符串
 * @returns {string} 格式化后的时间字符串
 */
function formatTimestamp(timestamp, format = DATE_FORMATS.YYYY_MM_DD_HH_MM_SS) {
  return formatDate(new Date(timestamp), format);
}

/**
 * 获取时间差
 * @param {Date|string|number} date1 - 日期1
 * @param {Date|string|number} date2 - 日期2
 * @param {string} unit - 时间单位
 * @returns {number} 时间差
 */
function getTimeDifference(date1, date2, unit = TIME_UNITS.MILLISECOND) {
  const d1 = new Date(date1);
  const d2 = new Date(date2);
  
  if (isNaN(d1.getTime()) || isNaN(d2.getTime())) return 0;
  
  const diffMs = Math.abs(d2.getTime() - d1.getTime());
  
  switch (unit) {
    case TIME_UNITS.MILLISECOND:
      return diffMs;
    case TIME_UNITS.SECOND:
      return Math.floor(diffMs / 1000);
    case TIME_UNITS.MINUTE:
      return Math.floor(diffMs / (1000 * 60));
    case TIME_UNITS.HOUR:
      return Math.floor(diffMs / (1000 * 60 * 60));
    case TIME_UNITS.DAY:
      return Math.floor(diffMs / (1000 * 60 * 60 * 24));
    case TIME_UNITS.WEEK:
      return Math.floor(diffMs / (1000 * 60 * 60 * 24 * 7));
    case TIME_UNITS.MONTH:
      return Math.floor(diffMs / (1000 * 60 * 60 * 24 * 30));
    case TIME_UNITS.YEAR:
      return Math.floor(diffMs / (1000 * 60 * 60 * 24 * 365));
    default:
      return diffMs;
  }
}

/**
 * 获取日期信息
 * @param {Date|string|number} date - 日期
 * @returns {Object} 日期信息
 */
function getDateInfo(date) {
  const d = new Date(date);
  if (isNaN(d.getTime())) return null;
  
  return {
    year: d.getFullYear(),
    month: d.getMonth() + 1,
    day: d.getDate(),
    hour: d.getHours(),
    minute: d.getMinutes(),
    second: d.getSeconds(),
    millisecond: d.getMilliseconds(),
    dayOfWeek: d.getDay(),
    dayOfYear: Math.floor((d - new Date(d.getFullYear(), 0, 0)) / 86400000),
    weekNumber: getWeekNumber(d),
    isLeapYear: isLeapYear(d.getFullYear()),
    timestamp: d.getTime()
  };
}

// 支持多种导出方式
if (typeof module !== 'undefined' && module.exports) {
  // Node.js 环境
  module.exports = {
    // 函数式导出
    formatDate,
    parseDate,
    getTimeAgo,
    isValidDate,
    addDays,
    addHours,
    addMinutes,
    addMonths,
    addYears,
    getDateRange,
    timezoneConvert,
    getWeekNumber,
    isLeapYear,
    getAge,
    getDaysInMonth,
    getFirstDayOfMonth,
    getLastDayOfMonth,
    getFirstDayOfWeek,
    getLastDayOfWeek,
    compareDates,
    isDateInRange,
    getTimestamp,
    fromTimestamp,
    getCurrentTimestamp,
    formatTimestamp,
    getTimeDifference,
    getDateInfo,
    // 常量导出
    TIME_UNITS,
    DATE_FORMATS
  };
} else if (typeof window !== 'undefined') {
  // 浏览器环境
  window.formatDate = formatDate;
  window.parseDate = parseDate;
  window.getTimeAgo = getTimeAgo;
  window.isValidDate = isValidDate;
  window.addDays = addDays;
  window.addHours = addHours;
  window.addMinutes = addMinutes;
  window.addMonths = addMonths;
  window.addYears = addYears;
  window.getDateRange = getDateRange;
  window.timezoneConvert = timezoneConvert;
  window.getWeekNumber = getWeekNumber;
  window.isLeapYear = isLeapYear;
  window.getAge = getAge;
  window.getDaysInMonth = getDaysInMonth;
  window.getFirstDayOfMonth = getFirstDayOfMonth;
  window.getLastDayOfMonth = getLastDayOfMonth;
  window.getFirstDayOfWeek = getFirstDayOfWeek;
  window.getLastDayOfWeek = getLastDayOfWeek;
  window.compareDates = compareDates;
  window.isDateInRange = isDateInRange;
  window.getTimestamp = getTimestamp;
  window.fromTimestamp = fromTimestamp;
  window.getCurrentTimestamp = getCurrentTimestamp;
  window.formatTimestamp = formatTimestamp;
  window.getTimeDifference = getTimeDifference;
  window.getDateInfo = getDateInfo;
  window.TIME_UNITS = TIME_UNITS;
  window.DATE_FORMATS = DATE_FORMATS;
}
